/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SLE_CONNECT_STATE_MACHINE_H
#define SLE_CONNECT_STATE_MACHINE_H

#include "sle_timer.h"
#include "sle_address_parcel.h"
#include "sle_connect_config.h"
#include "sle_state_machine.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
const std::string STATE_IDLE = "Idle";
const std::string STATE_CONNECTING = "Connecting";
const std::string STATE_CONNECTED = "Connected";
const std::string STATE_DISCONNECTING = "Disconnecting";
const std::string STATE_DISCONNECTED = "Disconnected";

const int SLE_CONNECT_TIMEOUT = 10500;                  //单位ms，海思sdk超时时间10s
const int SLE_CONNECT_UPDATE_PARAM_TIMEOUT = 10500;     //单位ms，海思sdk超时时间10s

enum SleConnectRole{
    CONNECT_ROLE_SLAVE,
    CONNECT_ROLE_MASTER,
};

enum SleConnectStateMessage {
    MSG_CONNECT,
    MSG_CONNECT_CMP,
    MSG_DISCONNECT,
    MSG_DISCONNECT_CMP,
    MSG_PARAM_UPDATE_REQ,
    MSG_PARAM_UPDATE_RSP,
    MSG_CONNECT_TIMEOUT,
};

typedef struct {
    SleConnectState state;
    SlePairState pairState;
    SleDisConnectReason reason;
} SleConnectCbInfo;

typedef struct {
    SleErrorCode errCode;
    SleConnectionParamUpdateEvt param;
} SleConnectParamCompleteCbInfo;

class SleConnectStateMachine;

class Device {
public:
    Device(SleAddress addr);
    Device(SleAddress addr, uint16_t connId);
    ~Device() = default;

    SleAddress GetSleAddress()
    {
        return addr_;
    }

    bool operator==(const Device &rhs) const
    {
        return (addr_ == rhs.addr_);
    }

    uint16_t &ConnId()
    {
        return connId_;
    }

    SleConnectStateMachine *SM() {
        return stateMachine_.get();
    }

    Timer *Tm() {
        return connTimer_.get();
    }

    int32_t &Role() {
        return role_;
    }

    void SetConnectCbInfo(const SleConnectCbInfo info)
    {
        connectCbInfo_ = info;
    }

    SleConnectCbInfo &GetConnectCbInfo()
    {
        return connectCbInfo_;
    }

    void SetConnectParamInfo(const SleConnectParamCompleteCbInfo info)
    {
        connectParamInfo_ = info;
    }

    SleConnectParamCompleteCbInfo &GetConnectParamInfo()
    {
        return connectParamInfo_;
    }

    void SetConnectState(const SleConnectState state)
    {
        state_ = state;
    }

    SleConnectState &GetConnectState()
    {
        return state_;
    }

private:
    uint16_t connId_ = 0xFFFF;
    SleAddress addr_ = {};
    int32_t role_ = CONNECT_ROLE_SLAVE;
    SleConnectCbInfo connectCbInfo_ {};
    SleConnectParamCompleteCbInfo connectParamInfo_ {};
    SleConnectState state_ = SLE_CONNECT_DISCONNECTED_STATE;
    std::unique_ptr<Timer> connTimer_ = nullptr;
    std::unique_ptr<SleConnectStateMachine> stateMachine_ = nullptr;
};

class SleConnectStateMachine : public StateMachine {
public:
    SleConnectStateMachine(Device &device) : device_(device) {};
    ~SleConnectStateMachine() = default;
    SleErrorCode Initialize();

private:
    Device &device_;
};

class Idle : public State {
public:
    Idle(SleConnectStateMachine &stateMachine, const std::string &name, Device &device)
        : State(name), connStateMachine_(stateMachine), device_(device) {};
    ~Idle() = default;

    bool Entry() override;
    void Exit() override;
    bool Dispatch(const Message &msg) override;

private:
    SleConnectStateMachine &connStateMachine_;
    Device &device_;
};

class Connecting : public State {
public:
    Connecting(SleConnectStateMachine &stateMachine, const std::string &name, Device &device)
        : State(name), connStateMachine_(stateMachine), device_(device) {};
    ~Connecting() = default;

    bool Entry() override;
    void Exit() override;
    bool Dispatch(const Message &msg) override;


private:
    SleConnectStateMachine &connStateMachine_;
    Device &device_;
};

class Connected : public State {
public:
    Connected(SleConnectStateMachine &stateMachine, const std::string &name, Device &device)
        : State(name), connStateMachine_(stateMachine), device_(device) {};
    ~Connected() = default;

    bool Entry() override;
    void Exit() override;
    bool Dispatch(const Message &msg) override;

private:
    SleConnectStateMachine &connStateMachine_;
    Device &device_;
};

class Disconnecting : public State {
public:
    Disconnecting(SleConnectStateMachine &stateMachine, const std::string &name, Device &device)
        : State(name), connStateMachine_(stateMachine), device_(device) {};
    ~Disconnecting() = default;

    bool Entry() override;
    void Exit() override;
    bool Dispatch(const Message &msg) override;

private:
    SleConnectStateMachine &connStateMachine_;
    Device &device_;
};

class Disconnected : public State {
public:
    Disconnected(SleConnectStateMachine &stateMachine, const std::string &name, Device &device)
        : State(name), connStateMachine_(stateMachine), device_(device) {};
    ~Disconnected() = default;

    bool Entry() override;
    void Exit() override;
    bool Dispatch(const Message &msg) override;

private:
    SleConnectStateMachine &connStateMachine_;
    Device &device_;
};
} // SleStandard
} // NearLink
} // OHOS

#endif //SLE_CONNECT_STATE_MACHINE_H